package com.bdmc.common.utils.wechat;

import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.InvalidParameterSpecException;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import cn.hutool.json.JSONUtil;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

/**
 * 微信手机号解密工具类
 */
public class AESForWeixinGetPhoneNumber {
    // 加密方式
    private static final String keyAlgorithm = "AES";
    // 避免重复new生成多个BouncyCastleProvider对象，因为GC回收不了，会造成内存溢出
    // 只在第一次调用decrypt()方法时才new 对象
    private static boolean initialized = false;
    // 用于Base64解密
    private final Base64.Decoder decoder = Base64.getDecoder();

    // 待解密的数据
    private final String originalContent;
    // 会话密钥sessionKey
    private final String encryptKey;
    // 加密算法的初始向量
    private final String iv;

    public AESForWeixinGetPhoneNumber(String originalContent, String encryptKey, String iv) {
        this.originalContent = originalContent;
        this.encryptKey = encryptKey;
        this.iv = iv;
    }

    /**
     * AES解密 填充模式AES/CBC/PKCS7Padding 解密模式128
     *
     * @return 解密后的信息对象
     */
    public WeixinPhoneDecryptInfo decrypt() {
        initialize();
        try {
            // 数据填充方式
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
            Key sKeySpec = new SecretKeySpec(decoder.decode(this.encryptKey), keyAlgorithm);
            // 初始化
            cipher.init(Cipher.DECRYPT_MODE, sKeySpec, generateIV(decoder.decode(this.iv)));
            byte[] data = cipher.doFinal(decoder.decode(this.originalContent));
            String datastr = new String(data, StandardCharsets.UTF_8);
            return JSONUtil.toBean(datastr, WeixinPhoneDecryptInfo.class);
        } catch (Exception e) {
            System.out.println(e.getMessage());
            return null;
        }
    }

    /** BouncyCastle作为安全提供，防止我们加密解密时候因为jdk内置的不支持改模式运行报错。 **/
    private static void initialize() {
        if (initialized)
            return;
        Security.addProvider(new BouncyCastleProvider());
        initialized = true;
    }

    // 生成iv
    private static AlgorithmParameters generateIV(byte[] iv)
            throws NoSuchAlgorithmException, InvalidParameterSpecException {
        AlgorithmParameters params = AlgorithmParameters.getInstance(keyAlgorithm);
        params.init(new IvParameterSpec(iv));
        return params;
    }
}
